package com.stottlerhenke.simbionic.editor.gui;

import java.awt.Component;
import java.awt.Dimension;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

import com.stottlerhenke.simbionic.editor.Util;
import com.stottlerhenke.simbionic.util.ClassSpecificationGenerator;


/**
 * A dialog for generating Class Specification from Class files or jars
 * 
 * There are two class spec generators. One of them  uses javadoc to generate class spec from java source files (I will call it javadoc version).
 * The other is from an existing Simbionic class that generate the class spec from a list of java classes (I will call it SB version). 
 * 
 * This dialog can process: 
 *	1. java source fullpath filename (method generateClassSpecFromSource, javadoc version) 
 *	2. jar name (extract all the classes from the jar file and process them (method generateClassSpecFromJar, SB version)
 *  3. java source folder containing java source files (method generateClassSpecFromSourceFolder, javadoc version) 
 *
 *	The dialog has the following components:
 *	
 *  JPanel javaSource: 
 *	java source filename (textfield)   generate (button1)
 *	This processes all 3 options above. It checks if the file is a directory. If so, case 3 is used.
 *  If not, it checks the extension of the file. if it's .java, it will generate the class spec (using javadoc version)
 *	if it's .jar, it will internally use the jar file as the classpath and before generating the class spec.
 *	texfield 4 is not required. (using SB version)
 *
 * 
 *
 */
public class ClassSpecGeneratorDialog extends ModalDialog
{
	public static String TITLE = "Generate Class Specification";
	
	
	private static final String GENERIC_ERROR_TITLE = "Failed to generate";
	
	protected static final String INPUT_FILE_NOT_FOUND = "Input file not found.";
	protected static final String INPUT_NOT_FOUND = "Input not found.";
	protected static final String DEFAULT_OUTPUT_LOCATION = "temp";
	protected static final String DEFAULT_OUTPUT_FILENAME= "defaultClassSpec.txt";
	protected static final String DEFAULT_ERROR_MESSAGE = "Error generating class specification file";
	protected static final String OUTPUT_PATH_NOT_FOUND = "Output file not found.";
	
	protected static final String INPUT_LABEL = "Input classes from:";
	private static final String OUTPUT_LABEL = "Output Class Specification to:";

	private static final int MAX_NUM_CHAR = 65;
	private static final int TOOLTIP_WIDTH = 300;
	
    protected JTextField _javaSourceTextField;
    protected JTextField _outputTextField;
    protected boolean _importDirectly;
    
    
    private static ClassSpecGeneratorDialog instance;
    
    public static ClassSpecGeneratorDialog getInstance()
    {
    	if (instance == null)
    		instance = new ClassSpecGeneratorDialog();
    	return instance;
    }
    
    /**
     * Constructor
     *
     */
    private ClassSpecGeneratorDialog()
    {
        super(TITLE);     
        this.setSize(300, this.getHeight());
   }

    protected void initGUI(){
        JPanel editPanel = new JPanel();
        editPanel.setLayout(new BoxLayout(editPanel, BoxLayout.Y_AXIS));
        editPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));

        JLabel label = new JLabel(INPUT_LABEL);
        editPanel.add(label);
        editPanel.add(Box.createRigidArea(new Dimension(0, 5)));
        editPanel.add(createJavaFilePanel());
        editPanel.add(Box.createRigidArea(new Dimension(0, 7)));
      
        // for the output doclet file
        label = new JLabel(OUTPUT_LABEL);
	    editPanel.add(label);
	    editPanel.add(Box.createRigidArea(new Dimension(0, 5)));
	    editPanel.add(createOutputPanel());
	    editPanel.add(Box.createRigidArea(new Dimension(0, 7)));
        
        initDialog(editPanel, null);
        
        updateOKButtonState();
    }
    
    private void updateOKButtonState()
    {
    	String text1 = _javaSourceTextField.getText();
    	String text2 = _outputTextField.getText();
    	_okButton.setEnabled(!(text1 == null || text2 == null || 
    			text1.trim().length() <= 0 || text2.trim().length() <= 0));
    }
    
    /**
     *  create a javaSource JPanel with a textfield for java source filename 
     *  The textfield can accept both .java and .jar files, and folders
     * @return JPanel
     */
    protected JPanel createJavaFilePanel(){
        JPanel javaSourcePanel = new JPanel();
        javaSourcePanel.setLayout(new BoxLayout(javaSourcePanel, BoxLayout.X_AXIS));
        javaSourcePanel.setAlignmentX(Component.LEFT_ALIGNMENT);
        String dialogTitle = "Input java source";
        ArrayList inputComponents = getTextFieldWithFileChooser(dialogTitle, null, null);
        _javaSourceTextField = (JTextField)inputComponents.get(1);
       
        FileChooserAction fileChooser = (FileChooserAction)inputComponents.get(3);
        setupFileChooser(fileChooser);
        
        _javaSourceTextField.getDocument().addDocumentListener(new TextFieldDocumentListener());

        return (JPanel)inputComponents.get(0);
    }
    
    protected void setupFileChooser(FileChooserAction fileChooser){
    	fileChooser.getFileChooser().addChoosableFileFilter(
    			Util.createFileFilterForExt("jar", "Jar File (.jar)"));
    			
    	fileChooser.getFileChooser().addChoosableFileFilter(
    			Util.createFileFilterForExt("java", "Java Source File (.java)"));
    	
    	fileChooser.getFileChooser().setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
    }
    
       
    /**
     * create the JPanel that contains a text field for output class spec filename
     * @return JPanel panel containing a text field for output filename
     */
    protected JPanel createOutputPanel(){
        JPanel outputPanel = new JPanel();
        outputPanel.setLayout(new BoxLayout(outputPanel, BoxLayout.X_AXIS));
        outputPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
        
        String dialogTitle = OUTPUT_LABEL;
        String extDesc = "SimBionic Class Specification File (.txt)";
        ArrayList outputComponents = getTextFieldWithFileChooser(dialogTitle, extDesc, "txt");
        _outputTextField = (JTextField)outputComponents.get(1);
        
        _outputTextField.getDocument().addDocumentListener(new TextFieldDocumentListener());
        
        return (JPanel)outputComponents.get(0);
    }
    

    protected void generate()
    {
    	String input = _javaSourceTextField.getText().trim();
    	String output = _outputTextField.getText().trim();
    	
		File inputFile = new File(input);
		File outputFile = new File(output);
		
		if (inputFile.isDirectory())
		{
			try
			{
				ClassSpecificationGenerator.createForSourceFolder(input, 
						outputFile.getParent(), outputFile.getName());
			}
			catch (ClassNotFoundException ex)
			{
				JOptionPane.showMessageDialog(this, 
						"Missing tools.jar for Javadoc support.", GENERIC_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
			}
			catch (Exception ex)
			{
				JOptionPane.showMessageDialog(this, 
						ex.getMessage(), GENERIC_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
			}
		}
		
		else if (input.toLowerCase().endsWith(".jar"))
		{
	    	try
	    	{
				ClassSpecificationGenerator.createForAllClassesFromJar(input, output);
	    	}
	    	catch (ClassNotFoundException ex)
	    	{
				JOptionPane.showMessageDialog(this, 
						"Cannot find class in classpath.\n"+ex.getMessage(), 
						GENERIC_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
	    	}
	    	catch (MalformedURLException ex)
	    	{
	    		JOptionPane.showMessageDialog(this, 
	    				"\""+input+"\" is not a valid location for a Jar file.", 
	    				GENERIC_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
	    	}
	    	catch (IOException ex)
	    	{
				JOptionPane.showMessageDialog(this, 
						"IO exception happened while generating class specification.\n"+ex.getMessage(), 
						GENERIC_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
	    	}
			catch (Exception ex)
			{
				JOptionPane.showMessageDialog(this, 
						ex.getMessage(), GENERIC_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
			}
		}
		
		else if (input.toLowerCase().endsWith(".java"))
		{
			try
			{
				ClassSpecificationGenerator.createForSource(input,
						outputFile.getParent(), outputFile.getName());
			}
			catch (ClassNotFoundException ex)
			{
				JOptionPane.showMessageDialog(this, 
						"Missing tools.jar for Javadoc support.", GENERIC_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
			}
			catch (Exception ex)
			{
				JOptionPane.showMessageDialog(this, 
						ex.getMessage(), GENERIC_ERROR_TITLE, JOptionPane.ERROR_MESSAGE);
			}
		}
		
		else
			JOptionPane.showMessageDialog(this, 
					"Cannot generate class specification for \""+input+"\".\n"+
					"Please select a Jar file, a Java file or a folder that contains Java files.", 
					"Invalid Input", JOptionPane.ERROR_MESSAGE);
    }
    
   
    
    /**
     * @see com.stottlerhenke.simbionic.editor.gui.StandardDialog#onOk()
     */
    @Override
    protected void onOk(){
      	super.onOk();
      	generate();
    }
    
    class TextFieldDocumentListener implements DocumentListener
    {
    	public void changedUpdate(DocumentEvent e){ updateOKButtonState(); }
    	public void removeUpdate(DocumentEvent e){ updateOKButtonState(); }
    	public void insertUpdate(DocumentEvent e){ updateOKButtonState(); }
    }
    
}
